package de.justphil.tcg.tcgserver.commons.domain;


import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import de.justphil.tcg.tcgserver.commons.config.GameConfig;
import de.justphil.tcg.tcgserver.commons.util.AtomicIdGenerator;
import de.justphil.tcg.tcgserver.commons.util.DateTimeUtil;


@Entity
@Table(name = "games", schema = "tcg")
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Game implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -4202098854864422502L;

	@Id
	@Column(name = "game_id")
	@XmlElement
	private long id;
	
	//@JoinColumn(name = "user_id", referencedColumnName = "user_id")
    //@ManyToOne(fetch=FetchType.EAGER)
	// foreign key mapping the associated user
	@Column(name = "winner_id")
    @XmlElement
	private long winnerId;
	
	/*
	@JoinTable(name = "game_players", joinColumns = {
	        @JoinColumn(name = "game_id", referencedColumnName = "game_id")}, inverseJoinColumns = {
	        @JoinColumn(name = "user_id", referencedColumnName = "user_id")})
    @ManyToMany(fetch=FetchType.EAGER)
    */
	@Transient
    private Set<Long> players;

	@Column(name = "state")
	@XmlElement
	private int state;
	
	@Column(name = "created")
	@Temporal(TemporalType.TIMESTAMP)
	private Date created;
	
	@Column(name = "modified")
	@Temporal(TemporalType.TIMESTAMP)
	private Date modified;
	
	
	
	public Game() {
		// JPA requires default constructor with no parameters
		
		this.players = new HashSet<Long>(GameConfig.NUMBER_OF_PLAYERS_PER_GAME);
	}
	
	

	public Game(int state) {
		this();
		
		this.id = AtomicIdGenerator.nextGameId();
		
		setState(state);
		
		long nowUTC = DateTimeUtil.getUTCTimeInMillis();
		this.created = new Date(nowUTC);
		this.modified = new Date(nowUTC);
	}



	public long getId() {
		return id;
	}

	public long getWinnerId() {
		return winnerId;
	}
	
	public Set<Long> getPlayers() {
		return players;
	}
	
	public int getState() {
		return state;
	}

	public Date getCreated() {
		return created;
	}

	public Date getModified() {
		return modified;
	}

	public void setId(long id) {
		this.id = id;
	}

	public void setWinnerId(long winnerId) {
		this.winnerId = winnerId;
	}
	
	public void setPlayers(Set<Long> players) {
		this.players = players;
	}
	
	public void setState(int state) {
		this.state = state;
	}

	public void setCreated(Date created) {
		this.created = created;
	}

	public void setModified(Date modified) {
		this.modified = modified;
	}
	
	/* ############################################################################################ */
	/* ############################################################################################ */
	/* ############################################################################################ */
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(255);
		
		sb.append("Game [id=").append(id).append(", winnerId=");
		
		sb.append(winnerId);
		
		sb.append(", state=").append(state).append("]");
		
		return sb.toString();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}



	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Game other = (Game) obj;
		if (id != other.id)
			return false;
		return true;
	}

	/* ############################################################################################ */
	/* ############################################################################################ */
	/* ############################################################################################ */


	/*
	@Override
	public void readData(DataInput in) throws IOException {
		id = in.readLong();
		state = new Integer(in.readInt());
		created = new Date(in.readLong());
		modified = new Date(in.readLong());
		
		boolean isWinner = in.readBoolean();
		if (isWinner) {
			winner = new User();
			winner.readData(in);
		}
		else {
			winner = null;
		}
		
		int playerListSize = in.readInt();
		User player = null;
		playerList = new ArrayList<User>(playerListSize);
		for (int i = 0; i < playerListSize; i++) {
			player = new User();
			player.readData(in);
			playerList.add(player);
		}
	}

	@Override
	public void writeData(DataOutput out) throws IOException {
		out.writeLong(id);
		out.writeInt(state.intValue());
		out.writeLong(created.getTime());
		out.writeLong(modified.getTime());
		
		boolean isWinner = winner != null;
		out.writeBoolean( isWinner );
		
		if (isWinner) {
			winner.writeData(out);
		}
		
		out.writeInt(playerList.size());
		for (User player : playerList) {
			player.writeData(out);
		}
	}
	*/



	public class State {
		public static final int WAITING		= 1;
		public static final int PENDING		= WAITING + 1;
		public static final int GAME_EXPIRED= WAITING + 2;
		public static final int GAME_OVER	= WAITING + 3;
	}

}
